package ThreadTest;


//举个线程不安全的例子：两个线程对同一个整型变量进行自增
//从cpu角度来分析count++可知：正是由于线程的抢占式执行，执行顺序是随机的，导致结果并没有达到10w
/*class Counter {
    public int count = 0;

    public void increse(){
         synchronized(this){
            count++
     }
}//锁对象，针对具体哪一个对象加锁

    synchronized public void increse() {//解决抢占式执行的方法就是加锁：synchronized，此时进入increse方法就会自动加锁，离开就会解锁
        count++;                        //当一个线程加锁成功后，其他线程要想加锁就会触发阻塞等待(BLOCKED)，直到占用锁的线程解锁
    }                                   //这里的加锁就把乱序的并发变成了串行操作，此时结果为10w
}                                       //实际开发中一个线程会有很多步骤，只需要将涉及线程安全的步骤加锁就行


public class ThreadSafety {
    public static void main(String[] args) throws InterruptedException {

        Counter counter = new Counter();

        Thread t1 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.increse();
            }
        });
        Thread t2 = new Thread(() -> {
            for (int i = 0; i < 50000; i++) {
                counter.increse();
            }
        });


        t1.start();
        t2.start();

        t1.join();
        t2.join();

        System.out.println(counter.count);//自增十万次，但是结果并没有达到
    }
}*/



//产生线程不安全的原因
//1、线程是抢占式执行的，线程的调度充满随机性   synchronized
//2、多个线程对同一个变量进行修改   synchronized
//3、针对变量的操作不是原子的    synchronized
//4、内存可见性  synchronized,volatile
//5、指令重排序  synchronized


import java.util.Scanner;

//对于内存可见性：例如一个线程进行循环读操作，一个线程进行修改操作
//解决方法：1、synchronized：可以保证原子性，内存可见性，也可以手动禁用编译器的优化操作
//        2、volatile：可以保证内存可见性，禁止优化操作，编译器每次执行 判定相等，都会重新从内存中读取isquick的值
public class ThreadSafety{
    public static volatile int isquick =0;

    public static void main(String[] args) {
        Thread thread = new Thread(() ->{
            //循环的从内存中读取非常低效
           while (isquick == 0){
               //此时thread有一个大胆的想法，不在从内存中读取了，直接从寄存器中读取------代码优化产生的效果
           }
            System.out.println("线程thread结束");
        });
        thread.start();


        Scanner scanner = new Scanner(System.in);
        System.out.println("请输入：");
        isquick = scanner.nextInt();//此时修改isquick的值为1，thread线程不能感知到，该循环还在继续
        System.out.println("main线程结束");
    }
}
